package com.csu.letaobackend.serviceM.impl;

import com.alipay.api.domain.ItemModel;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.csu.letaobackend.bean.*;
import com.csu.letaobackend.commom.CommonResponse;
import com.csu.letaobackend.persistence.*;
import com.csu.letaobackend.serviceM.StatisticsMService;
import com.csu.letaobackend.vo.*;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.*;

@Service
@MapperScan("com.csu.letaobackend.persistence")
public class StatisticsMServiceImpl implements StatisticsMService {

      private static long DAY = 86400000;//一天的毫秒


      @Autowired
      OrderDao orderDao;

      @Autowired
      OrderItemDao orderitemDao;

      @Autowired
      ItemDao itemDao;

      @Autowired
      ShopDao shopDao;

      @Autowired
      ReceivingDao receivingDao;

      @Autowired
      PictureDao pictureDao;

      @Autowired
      RefundserviceDao refundserviceDao;

      @Autowired
      CouponDao couponDao;

      @Autowired
      SpecialofferDao specialofferDao;

      @Autowired
      UserDao userDao;

      @Autowired
      SellerDao sellerDao;

      @Autowired
      CategoryDao categoryDao;

      @Autowired
      ProductDao productDao;

      @Autowired
      ItemevalDao itemevalDao;

      @Autowired
      BrowsingrecordDao browsingrecordDao;

      @Override
      public CommonResponse<IncomeVO> getDayIncome() {
            IncomeVO incomeVO = new IncomeVO();
            Date date = transferDate(new Date());//清空时分秒

            incomeVO.setGeneralincome(getIncome(date, new Date(date.getTime() + DAY)));
            return CommonResponse.createForSuccess(incomeVO);
      }

      @Override
      public CommonResponse<IncomeVO> getWeekIncome() {
            IncomeVO incomeVO = new IncomeVO();
            Date date = transferDate(new Date());//清空时分秒

            incomeVO.setGeneralincome(getIncome(new Date(date.getTime() - 6 * DAY), new Date()));
            List<Double> list = new ArrayList<>();
            list.add(getIncome(new Date(date.getTime() - 6 * DAY), new Date(date.getTime() - 5 * DAY)));
            list.add(getIncome(new Date(date.getTime() - 5 * DAY), new Date(date.getTime() - 4 * DAY)));
            list.add(getIncome(new Date(date.getTime() - 4 * DAY), new Date(date.getTime() - 3 * DAY)));
            list.add(getIncome(new Date(date.getTime() - 3 * DAY), new Date(date.getTime() - 2 * DAY)));
            list.add(getIncome(new Date(date.getTime() - 2 * DAY), new Date(date.getTime() - 1 * DAY)));
            list.add(getIncome(new Date(date.getTime() - 1 * DAY), date));
            list.add(getIncome(date, new Date()));
            incomeVO.setIncome(list);
            return CommonResponse.createForSuccess(incomeVO);
      }

      @Override
      public CommonResponse<IncomeVO> getMonthIncome() {
            IncomeVO incomeVO = new IncomeVO();
            Date date = transferDateMonth(new Date());
            incomeVO.setGeneralincome(getIncome(date,new Date()));

            return CommonResponse.createForSuccess(incomeVO);
      }

      @Override
      public CommonResponse<IncomeVO> getYearIncome() {
            IncomeVO incomeVO = new IncomeVO();
            Date date = transferDateMonth(new Date());

            List<Double> list = new ArrayList<>();
            list.add(getIncome(date, new Date()));
            list.add(getRecentMonthIncome(addMonth(date, -0)));
            list.add(getRecentMonthIncome(addMonth(date, -1)));
            list.add(getRecentMonthIncome(addMonth(date, -2)));
            list.add(getRecentMonthIncome(addMonth(date, -3)));
            list.add(getRecentMonthIncome(addMonth(date, -4)));
            list.add(getRecentMonthIncome(addMonth(date, -5)));
            list.add(getRecentMonthIncome(addMonth(date, -6)));
            list.add(getRecentMonthIncome(addMonth(date, -7)));
            list.add(getRecentMonthIncome(addMonth(date, -8)));
            list.add(getRecentMonthIncome(addMonth(date, -9)));
            list.add(getRecentMonthIncome(addMonth(date, -10)));
            Collections.reverse(list);
            double sum = 0;
            for (double i : list) {
                  sum += i;
            }
            incomeVO.setGeneralincome(sum);
            incomeVO.setIncome(list);
            return CommonResponse.createForSuccess(incomeVO);
      }

      @Override
      public CommonResponse getUserNum() {
            int usernum = userDao.selectList(null).size();
            return CommonResponse.createForSuccess(usernum);
      }

      @Override
      public CommonResponse getSellerNum() {
            int sellernum = sellerDao.selectList(null).size();

            return CommonResponse.createForSuccess(sellernum);
      }

      @Override
      public CommonResponse getShopNum() {
            int shopnum = shopDao.selectList(null).size();

            return CommonResponse.createForSuccess(shopnum);
      }

      @Override
      public CommonResponse getItemNum() {
            int itemnum = itemDao.selectList(null).size();
            return CommonResponse.createForSuccess(itemnum);
      }

      @Override
      public CommonResponse<RefundVO> getWeekRefund() {
            RefundVO refundVO = new RefundVO();
            Date date = transferDate(new Date());//清空时分秒

            refundVO.setGeneralrefund(getRefund(new Date(date.getTime() - 6 * DAY), new Date()));
            List<Double> list = new ArrayList<>();
            list.add(getRefund(new Date(date.getTime() - 6 * DAY), new Date(date.getTime() - 5 * DAY)));
            list.add(getRefund(new Date(date.getTime() - 5 * DAY), new Date(date.getTime() - 4 * DAY)));
            list.add(getRefund(new Date(date.getTime() - 4 * DAY), new Date(date.getTime() - 3 * DAY)));
            list.add(getRefund(new Date(date.getTime() - 3 * DAY), new Date(date.getTime() - 2 * DAY)));
            list.add(getRefund(new Date(date.getTime() - 2 * DAY), new Date(date.getTime() - 1 * DAY)));
            list.add(getRefund(new Date(date.getTime() - 1 * DAY), date));
            list.add(getRefund(date, new Date()));
            refundVO.setRefunds(list);
            return CommonResponse.createForSuccess(refundVO);
      }

      @Override
      public CommonResponse<RefundVO> getYearRefund() {
            RefundVO refundVO = new RefundVO();
            Date date = transferDateMonth(new Date());

            List<Double> list = new ArrayList<>();
            list.add(getRefund(date, new Date()));
            list.add(getRecentMonthRefund(addMonth(date, -0)));
            list.add(getRecentMonthRefund(addMonth(date, -1)));
            list.add(getRecentMonthRefund(addMonth(date, -2)));
            list.add(getRecentMonthRefund(addMonth(date, -3)));
            list.add(getRecentMonthRefund(addMonth(date, -4)));
            list.add(getRecentMonthRefund(addMonth(date, -5)));
            list.add(getRecentMonthRefund(addMonth(date, -6)));
            list.add(getRecentMonthRefund(addMonth(date, -7)));
            list.add(getRecentMonthRefund(addMonth(date, -8)));
            list.add(getRecentMonthRefund(addMonth(date, -9)));
            list.add(getRecentMonthRefund(addMonth(date, -10)));
            Collections.reverse(list);
            double sum = 0;
            for (double i : list) {
                  sum += i;
            }
            refundVO.setGeneralrefund(sum);
            refundVO.setRefunds(list);
            return CommonResponse.createForSuccess(refundVO);
      }

      private double getRefund(Date date, Date date1) {
            QueryWrapper<Order> queryWrapper = new QueryWrapper<>();
            List<Integer> list = new ArrayList<>(Arrays.asList(4, 5, 6));

            queryWrapper.between("ordertime", date, date1).in("status", list);
            List<Order> orderList = orderDao.selectList(queryWrapper);
            double refund = 0;
            for (Order order : orderList) {
                  refund += entityToVO(order).getActualpay();
            }
            return refund;
      }

      private double getRecentMonthRefund(Date date) {
            date = transferDateMonth(date);
            Date date1 = new Date(date.getTime() - DAY);

            return getRefund(transferDateMonth(date1), date);
      }

      @Override
      public CommonResponse<OrderNumVO> getWeekOrderNum() {
            OrderNumVO orderNumVO = new OrderNumVO();
            Date date = transferDate(new Date());//清空时分秒

            orderNumVO.setGeneralorders(countOrderNum(new Date(date.getTime() - 6 * DAY), new Date()));
            List<Integer> list = new ArrayList<>();
            list.add(countOrderNum(new Date(date.getTime() - 6 * DAY), new Date(date.getTime() - 5 * DAY)));
            list.add(countOrderNum(new Date(date.getTime() - 5 * DAY), new Date(date.getTime() - 4 * DAY)));
            list.add(countOrderNum(new Date(date.getTime() - 4 * DAY), new Date(date.getTime() - 3 * DAY)));
            list.add(countOrderNum(new Date(date.getTime() - 3 * DAY), new Date(date.getTime() - 2 * DAY)));
            list.add(countOrderNum(new Date(date.getTime() - 2 * DAY), new Date(date.getTime() - 1 * DAY)));
            list.add(countOrderNum(new Date(date.getTime() - 1 * DAY), date));
            list.add(countOrderNum(date, new Date()));
            orderNumVO.setOrders(list);
            return CommonResponse.createForSuccess(orderNumVO);
      }


      @Override
      public CommonResponse<OrderNumVO> getYearRefundNum() {
            OrderNumVO orderNumVO = new OrderNumVO();
            Date date = transferDateMonth(new Date());

            List<Integer> list = new ArrayList<>();
            list.add(countOrderNum(date, new Date()));
            list.add(countOrderNumMonthRefund(addMonth(date, -0)));
            list.add(countOrderNumMonthRefund(addMonth(date, -1)));
            list.add(countOrderNumMonthRefund(addMonth(date, -2)));
            list.add(countOrderNumMonthRefund(addMonth(date, -3)));
            list.add(countOrderNumMonthRefund(addMonth(date, -4)));
            list.add(countOrderNumMonthRefund(addMonth(date, -5)));
            list.add(countOrderNumMonthRefund(addMonth(date, -6)));
            list.add(countOrderNumMonthRefund(addMonth(date, -7)));
            list.add(countOrderNumMonthRefund(addMonth(date, -8)));
            list.add(countOrderNumMonthRefund(addMonth(date, -9)));
            list.add(countOrderNumMonthRefund(addMonth(date, -10)));
            Collections.reverse(list);
            int sum = 0;
            for (int i : list) {
                  sum += i;
            }
            orderNumVO.setGeneralorders(sum);
            orderNumVO.setOrders(list);
            return CommonResponse.createForSuccess(orderNumVO);
      }

      @Override
      public CommonResponse<List<CategorySellVO>> getCategorySell() {
            List<CategorySellVO> categorySellVOList = new ArrayList<>();
            for (Category category : categoryDao.selectList(null)) {
                  CategorySellVO categorySellVO = new CategorySellVO();
                  categorySellVO.setCategoryid(category.getId());
                  categorySellVO.setCategoryname(category.getName());
                  int sum = 0;
                  for (int itemid : getItemidsByCategoryId(category.getId())) {
                        sum += countItemNum(itemid);
                  }
                  categorySellVO.setSellnum(sum);

                  categorySellVOList.add(categorySellVO);
            }

            return CommonResponse.createForSuccess(categorySellVOList);
      }


      @Override
      public CommonResponse<List<ShopSellVO>> getShopSell() {

            List<ShopSellVO> shopSellVOList = new ArrayList<>();
            for (Shop shop : shopDao.selectList(null)) {
                  ShopSellVO shopSellVO = new ShopSellVO();
                  shopSellVO.setShopid(shop.getShopid());
                  shopSellVO.setShopname(shop.getName());
                  int sum = 0;
                  for (int itemid : getItemidsByShopId(shop.getShopid())) {
                        sum += countItemNum(itemid);
                  }
                  shopSellVO.setSellnum(sum);
                  shopSellVOList.add(shopSellVO);
            }
            return CommonResponse.createForSuccess(shopSellVOList);
      }

      @Override
      public CommonResponse<IPage<BrowsingrecordVO>> getRecords(int pageid, int pagesize) {
            IPage<Browsingrecord> browsingrecordIPage=new Page<>(pageid,pagesize);
            browsingrecordDao.selectPage(browsingrecordIPage,null);

            List<BrowsingrecordVO> browsingrecordVOList=new ArrayList<>();
            for(Browsingrecord browsingrecord: browsingrecordIPage.getRecords()){
                  browsingrecordVOList.add(entityToVO(browsingrecord));
            }
            IPage<BrowsingrecordVO> browsingrecordVOIPage=new Page<>(pageid,pagesize);
            browsingrecordVOIPage.setTotal(browsingrecordIPage.getTotal());
            browsingrecordVOIPage.setRecords(browsingrecordVOList);
            return CommonResponse.createForSuccess(browsingrecordVOIPage);
      }

      @Override
      public CommonResponse<IPage<BrowsingrecordVO>> searchRecords(String username, Date time, int pageid, int pagesize) {
            IPage<Browsingrecord> browsingrecordIPage=new Page<>(pageid,pagesize);
            QueryWrapper<Browsingrecord> queryWrapper = new QueryWrapper<>();
            queryWrapper.like("username",username).ge("time",time);
            browsingrecordDao.selectPage(browsingrecordIPage,queryWrapper);


            List<BrowsingrecordVO> browsingrecordVOList=new ArrayList<>();
            for(Browsingrecord browsingrecord: browsingrecordIPage.getRecords()){
                  browsingrecordVOList.add(entityToVO(browsingrecord));
            }
            IPage<BrowsingrecordVO> browsingrecordVOIPage=new Page<>(pageid,pagesize);
            browsingrecordVOIPage.setTotal(browsingrecordIPage.getTotal());
            browsingrecordVOIPage.setRecords(browsingrecordVOList);
            return CommonResponse.createForSuccess(browsingrecordVOIPage);
      }

      private List<Integer> getItemidsByCategoryId(int categoryid) {
            List<Integer> itemidList = new ArrayList<>();
            QueryWrapper<Product> queryWrapper = new QueryWrapper<>();
            queryWrapper.eq("categoryid", categoryid);
            for (Product product : productDao.selectList(queryWrapper)) {
                  QueryWrapper<Item> queryWrapper1 = new QueryWrapper<>();
                  queryWrapper1.eq("productid", product.getId());
                  for (Item item : itemDao.selectList(queryWrapper1)) {
                        itemidList.add(item.getId());
                  }
            }
            return itemidList;
      }

      private List<Integer> getItemidsByShopId(int shopid) {
            List<Integer> itemidList = new ArrayList<>();
            QueryWrapper<Item> queryWrapper = new QueryWrapper<>();
            queryWrapper.eq("shopid", shopid);
            for (Item item : itemDao.selectList(queryWrapper)) {
                  itemidList.add(item.getId());
            }
            return itemidList;
      }

      private int countItemNum(int itemid) {
            QueryWrapper<OrderItem> queryWrapper = new QueryWrapper<>();
            queryWrapper.eq("itemid", itemid);

            List<OrderItem> orderItemList = orderitemDao.selectList(queryWrapper);
            int sum = 0;
            for (OrderItem orderItem : orderItemList) {
                  sum += orderItem.getNum();
            }
            return sum;
      }

      private int countOrderNum(Date date, Date date1) {
            QueryWrapper<Order> queryWrapper = new QueryWrapper<>();
            queryWrapper.between("ordertime", date, date1);

            return orderDao.selectList(queryWrapper).size();
      }

      private int countOrderNumMonthRefund(Date date) {
            date = transferDateMonth(date);
            Date date1 = new Date(date.getTime() - DAY);

            return countOrderNum(transferDateMonth(date1), date);
      }


      private double getRecentMonthIncome(Date date) {
            date = transferDateMonth(date);
            Date date1 = new Date(date.getTime() - DAY);

            return getIncome(transferDateMonth(date1), date);
      }

      private double getIncome(Date date, Date date1) {
            QueryWrapper<Order> queryWrapper = new QueryWrapper<>();
            queryWrapper.between("ordertime", date, date1);
            List<Order> orderList = orderDao.selectList(queryWrapper);
            double income = 0;
            for (Order order : orderList) {
                  income += entityToVO(order).getActualpay();
            }
            return income;
      }

      private Date addMonth(Date date, int num) {
            Calendar instance = Calendar.getInstance();
            instance.setTime(date);
            instance.add(Calendar.MONTH, num);
            instance.set(Calendar.DAY_OF_MONTH, 1);
            instance.set(Calendar.HOUR_OF_DAY, 0);
            instance.set(Calendar.MINUTE, 0);
            instance.set(Calendar.SECOND, 0);
            instance.set(Calendar.MILLISECOND, 0);
            date = instance.getTime();
            return date;
      }


      private Date transferDate(Date date) {
            Calendar instance = Calendar.getInstance();
            instance.setTime(date);
            instance.set(Calendar.HOUR_OF_DAY, 0);
            instance.set(Calendar.MINUTE, 0);
            instance.set(Calendar.SECOND, 0);
            instance.set(Calendar.MILLISECOND, 0);
            date = instance.getTime();
            return date;
      }

      private Date transferDateMonth(Date date) {
            Calendar instance = Calendar.getInstance();
            instance.setTime(date);
            instance.set(Calendar.DAY_OF_MONTH, 1);
            instance.set(Calendar.HOUR_OF_DAY, 0);
            instance.set(Calendar.MINUTE, 0);
            instance.set(Calendar.SECOND, 0);
            instance.set(Calendar.MILLISECOND, 0);
            date = instance.getTime();
            return date;
      }

      private Date transferDateYear(Date date) {
            Calendar instance = Calendar.getInstance();
            instance.setTime(date);
            instance.set(Calendar.MONTH, 0);
            instance.set(Calendar.DAY_OF_MONTH, 0);
            instance.set(Calendar.HOUR_OF_DAY, 0);
            instance.set(Calendar.MINUTE, 0);
            instance.set(Calendar.SECOND, 0);
            instance.set(Calendar.MILLISECOND, 0);
            date = instance.getTime();
            return date;
      }

      private OrderVO entityToVO(Order order) {
            OrderVO orderVO = new OrderVO();
            orderVO.setOrderid(order.getOrderid());
            orderVO.setShopid(order.getShopid());
            orderVO.setUsername(order.getUsername());
            orderVO.setShopname(shopDao.selectById(order.getShopid()).getName());
            orderVO.setRecevingid(order.getRecevingid());
            orderVO.setStatus(order.getStatus());
            orderVO.setRecevingtime(order.getRecevingtime());
            orderVO.setOrdertime(order.getOrdertime());
            orderVO.setIsevaluate(order.getIsevaluate());
            orderVO.setIspay(order.getIspay());

            Receiving receving = receivingDao.selectById(order.getRecevingid());
            orderVO.setReceivingaddr(receving.getAddrcoutry() + receving.getAddrprovince() + receving.getAddrcouty() + receving.getAddrdetails());
            orderVO.setContactphone(receving.getContactphone());
            orderVO.setRecivename(receving.getReceivename());

            List<OrderItemVO> orderItemVOList = new ArrayList<>();
            UpdateWrapper updateWrapper = new UpdateWrapper();
            updateWrapper.eq("orderid", order.getOrderid());
            List<OrderItem> orderItemList = orderitemDao.selectList(updateWrapper);
            for (OrderItem orderitem : orderItemList) {
                  orderItemVOList.add(entityToVO(orderitem));
            }
            orderVO.setOrderItemVOList(orderItemVOList);
            orderVO.setCouponid(order.getCouponid());
            //设置coupondiscount
            if (order.getCouponid() == 0)
                  orderVO.setCoupondiscount(0);
            else {
                  double discount = couponDao.selectById(order.getCouponid()).getDiscount();
                  orderVO.setCoupondiscount(discount);
            }

            double ordertotal = 0;
            double orderdiscount = 0;
            for (OrderItemVO orderItemVO : orderItemVOList) {
                  ordertotal += orderItemVO.getAllprice();
                  orderdiscount += orderItemVO.getDiscount();
            }
            orderVO.setOrdertotal(ordertotal);
            orderVO.setOrderdiscount(orderdiscount);
            double actualpay = ordertotal - orderdiscount - orderVO.getCoupondiscount();
            orderVO.setActualpay(actualpay);

            if (refundserviceDao.selectOne(updateWrapper) == null)
                  orderVO.setServiceid(0);
            else
                  orderVO.setServiceid(refundserviceDao.selectOne(updateWrapper).getServiceid());
            return orderVO;
      }

      private OrderItemVO entityToVO(OrderItem orderitem) {
            Picture picture = pictureDao.selectById(orderitem.getItemid());
            Item item = itemDao.selectById(orderitem.getItemid());
            OrderItemVO orderitemVO = new OrderItemVO();
            orderitemVO.setOrderid(orderitem.getOrderid());
            orderitemVO.setItemid(orderitem.getItemid());
            orderitemVO.setDescription(item.getDescription());
            orderitemVO.setNum(orderitem.getNum());
            orderitemVO.setPrice(orderitem.getNewprice());
            orderitemVO.setAllprice(orderitem.getNewprice() * orderitem.getNum());
            orderitemVO.setAttrdescription(orderitem.getAttrdescription());
            orderitemVO.setSrc(picture.getSrc());
            if (specialofferDao.selectById(orderitem.getItemid()) != null)
                  orderitemVO.setSpecialrate(specialofferDao.selectById(orderitem.getItemid()).getRate());
            else
                  orderitemVO.setSpecialrate(1);
            orderitemVO.setDiscount(orderitem.getNewprice() * orderitem.getNum() * (1 - orderitemVO.getSpecialrate()));
            return orderitemVO;
      }

      private BrowsingrecordVO entityToVO(Browsingrecord browsingrecord) {
            Item item = itemDao.selectById(browsingrecord.getItemid());
            BrowsingrecordVO browsingrecordVO = new BrowsingrecordVO();
            browsingrecordVO.setUsername(browsingrecord.getUsername());
            browsingrecordVO.setTime(browsingrecord.getTime());
            browsingrecordVO.setItemid(browsingrecord.getItemid());
            browsingrecordVO.setPrice(item.getPrice());
            browsingrecordVO.setDescription(item.getDescription());
            browsingrecordVO.setStar(getAvgStar(item));
            browsingrecordVO.setStock(item.getStock());
            int pictureid = itemDao.selectById(browsingrecord.getItemid()).getPictureid();
            browsingrecordVO.setSrc(pictureDao.selectById(pictureid).getSrc());
            browsingrecordVO.setShopid(itemDao.selectById(browsingrecord.getItemid()).getShopid());
            browsingrecordVO.setShopname(shopDao.selectById(browsingrecordVO.getShopid()).getName());
            return browsingrecordVO;
      }

      private double getAvgStar(Item item) {
            QueryWrapper queryWrapper = new QueryWrapper();
            queryWrapper.eq("itemid", item.getId());
            List<Itemeval> itemevalList = itemevalDao.selectList(queryWrapper);
            double star = 0.0;
            double totalStar = 0.0;
            for (Itemeval itemeval : itemevalList) {
                  totalStar += itemeval.getStar();
            }
            if (itemevalList.size() > 0) {
                  star = new BigDecimal(totalStar / itemevalList.size()).setScale(1, BigDecimal.ROUND_HALF_UP).doubleValue();
            }
            return star;
      }
}
